#include "Sock.hpp"
#include <sys/epoll.h>
#include <unordered_map>

#define SIZE 128
#define NUM 64

void Usage(std::string proc)
{
    std::cout << "Usage \r\t" << proc << " port" << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    std::unordered_map<std::string, std::string> dict;
    dict["hello\n"] = "你好";
    dict["world\n"] = "世界";
    dict["apple\n"] = "苹果";
    dict["balana\n"] = "香蕉";

    // 1.创建tcp套接字、绑定套接字、监听套接字
    int listen_sock = Sock::Socket();
    // std::cout << listen_sock << std::endl; // 3
    Sock::Bind(listen_sock, (uint16_t)atoi(argv[1]));
    Sock::Listen(listen_sock);

    // 2.创建epoll模型,获得文件描述符epfd
    int epfd = epoll_create(SIZE);
    // std::cout << epfd << std::endl; // 4

    // 3.用户告诉内核：将listen_sock添加到epoll句柄中
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
    epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev);

    // 4.内核告诉用户
    struct epoll_event revs[NUM];
    for (;;)
    {
        int timeout = -1;
        //这里传入的数组，仅仅是尝试从内核中拿回来已经就绪的事件
        int n = epoll_wait(epfd, revs, NUM, timeout);
        switch (n)
        {
        case 0:
            std::cout << "time out" << std::endl;
            break;
        case -1:
            std::cerr << "wait errno" << std::endl;
            break;
        default:
            for (int i = 0; i < n; ++i)
            {
                std::cout << "fd: " << revs[i].data.fd << " 有事件就绪" << std::endl;
                if (revs[i].events & EPOLLIN)
                {
                    // 读就绪
                    std::cout << "fd: " << revs[i].data.fd << " 有读就绪事件" << std::endl;
                    // 5.1 处理链接事件
                    if (revs[i].data.fd == listen_sock)
                    {
                        std::cout << "fd: " << revs[i].data.fd << " 有新链接..." << std::endl;
                        int sock = Sock::Accept(listen_sock);
                        if (sock >= 0)
                        {
                            std::cout << "获取新链接成功: " << sock << std::endl;
                            struct epoll_event _ev;
                            _ev.events = EPOLLIN;
                            _ev.data.fd = sock;
                            epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &_ev);
                            std::cout << "已经将fd: " << sock << " 托管给epoll" << std::endl;
                        }
                    }
                    // 5.2 处理正常读取
                    else
                    {
                        std::cout << "fd: " << revs[i].data.fd << " 正常数据就绪" << std::endl;
                        // 此刻读取有问题 ———— 粘包问题
                        char buffer[1024];
                        ssize_t s = recv(revs[i].data.fd, buffer, sizeof(buffer) - 1, 0);
                        if (s > 0)
                        {
                            buffer[s] = 0;
                            std::cout << "client[" << revs[i].data.fd << "]# " << buffer << std::endl;

                            send(revs[i].data.fd, dict[std::string(buffer)].c_str(), dict[std::string(buffer)].size(), 0);
                            // 读取到之后可以将event修改为写
                            // struct epoll_event _ev;
                            // _ev.events = EPOLLOUT;
                            // _ev.events = revs[i].data.fd;
                            // epoll_ctl(epfd, EPOLL_CTL_MOD, revs[i].data.fd, &_ev);
                        }
                        else if (s == 0)
                        {
                            std::cout << "client[" << revs[i].data.fd << "] quit..." << std::endl;
                            close(revs[i].data.fd);
                            // 删除红黑树中的节点
                            epoll_ctl(epfd, EPOLL_CTL_DEL, revs[i].data.fd, nullptr);
                            std::cout << "fd: " << revs[i].data.fd << " delete from epoll success..." << std::endl;
                        }
                        else
                        {
                            std::cerr << "client[" << revs[i].data.fd << "] read errno" << std::endl;
                            close(revs[i].data.fd);
                            // 删除红黑树中的节点
                            epoll_ctl(epfd, EPOLL_CTL_DEL, revs[i].data.fd, nullptr);
                            std::cout << "fd: " << revs[i].data.fd << " delete from epoll success..." << std::endl;
                        }
                    }
                }
                else if (revs[i].events & EPOLLOUT)
                {
                    // 写就绪
                }
                else
                {
                    // TODO
                }
            }
            break;
        }
    }

    close(epfd);
    close(listen_sock);
    return 0;
}